package com.itao.handler;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.handler.WriteHandler;
import com.itao.annotation.DynamicHeadBean;
import com.itao.annotation.ExcelExport;
import com.itao.annotation.WriteHandlerBean;
import com.itao.config.SpringContextHolder;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * Excel返回值解析器
 *
 * @author sjt
 * @Date 2024/12/9 10:08
 */
public class ExcelReturnValueHandler implements HandlerMethodReturnValueHandler {
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return returnType.hasMethodAnnotation(ExcelExport.class);
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) {
        mavContainer.setRequestHandled(true);
        HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
        Assert.notNull(response, "HttpServletResponse为空");
        ExcelExport excel = returnType.getMethodAnnotation(ExcelExport.class);
        Assert.notNull(excel, "无Excel注解");
        String value = excel.value();
        Class<?> aClass = excel.returnType();
        boolean dynamicHead = excel.dynamicHead();

        if (returnValue == null) {
            throw new RuntimeException("返回值类型必须为List");
        }

        if (!(returnValue instanceof List<?> exportList)) {
            throw new RuntimeException("返回值类型必须为List");
        }

        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("UTF-8");
            String fileName = URLEncoder.encode(value + ".xlsx", StandardCharsets.UTF_8);
            response.setHeader("Content-disposition", "attachment;filename=" + fileName);
            OutputStream outputStream = response.getOutputStream();
            ExcelWriterSheetBuilder writerBuilder;
            if (dynamicHead) {
                String beanName = excel.headBeanName();
                if (beanName == null || beanName.isEmpty()) {
                    throw new RuntimeException("dynamicHead为true时需指定beanName属性");
                }
                DynamicHeadBean bean = SpringContextHolder.getBean(beanName);
                writerBuilder = EasyExcel.write(outputStream)
                        .head(bean.heads())
                        .sheet();
            } else {
                if (exportList.isEmpty() && aClass == void.class) {
                    throw new RuntimeException("返回值为空集合时必须指定returnType或动态头");
                }
                if (aClass == void.class) {
                    aClass = exportList.getFirst().getClass();
                }
                writerBuilder = EasyExcel.write(outputStream, aClass).sheet();
            }
            String beanName = excel.handlerBeanName();
            if (beanName != null && !beanName.isEmpty()) {
                WriteHandlerBean bean = SpringContextHolder.getBean(beanName);
                List<WriteHandler> writeHandlers = bean.writeHandlers();
                writeHandlers.forEach(writerBuilder::registerWriteHandler);
            }
            writerBuilder.doWrite(exportList);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
